#include "http_function.h"
//#include "opc_fun.h"

extern sqlite3 *db;
extern UA_Server *haussentech_opc_server;
extern struct modbus_client_info modbus_config;
//extern字符串数组的时候一定要注意把声明完整的带进来
//将内存里面装在进来的数据进行比较
#define MAX_ACCOUNT_NUM 32
//缓存中支持返回1千条数据
#define MAX_history_data_NUM 1024
extern char* temp_username[MAX_ACCOUNT_NUM];
extern char* temp_password[MAX_ACCOUNT_NUM];
//内存空间就分配一次，在OPC启动的时候opc_routine()函数中分配一次
//不释放该空间，每次请求进来的时候，重复利用
int http_colum_num = 0;
bool http_sql_cb_done = false;
char* temp_history_data_buffer[MAX_history_data_NUM];
char* temp_record_date_buffer[MAX_history_data_NUM];
/*
single global variable to store preprocess user param
*/
struct opc_var_config_info temp_config_info;
//接受内网穿透配置的缓冲区
struct frp_connect_info temp_frp_connect_info;
struct POST_OPC_UA_history_data temp_POST_OPC_UA_history_data;
struct program_update_info temp_program_update_info;
//modbus master
extern modbus_t *ctx;
// enum protocol{ 
//   modbus_rtu, 
//   modbus_tcp,
//   iec_104, 
//   dlt_645
// }pd;//protocol driver
//变量删除若成功，则重启程序
bool reboot = false;

//std::map<int, struct opc_var_config_info> config_collection;

const char *errorpage = "<html><body>This doesn’t seem to be right.</body></html>";
const char *greetingpage = "<html><body><h1>Welcome, %s!</center></h1></body></html>";
const char *askpage =
    "<html><body>\
  What’s your name, Sir?<br>\
  <form action=\"/namepost\" method=\"post\">\
  <input name=\"name\" type=\"text\">\
  <input type=\"submit\" value=\" Send \"></form>\
  </body></html>";

enum MHD_Result PP_update_frp_connect_info(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
  const char *filename, const char *content_type,
  const char *transfer_encoding, const char *data, uint64_t off, size_t size){
  struct connection_info_struct *con_info = coninfo_cls;
  (void)kind;              /* Unused. Silent compiler warning. */
  (void)filename;          /* Unused. Silent compiler warning. */
  (void)content_type;      /* Unused. Silent compiler warning. */
  (void)transfer_encoding; /* Unused. Silent compiler warning. */
  (void)off;               /* Unused. Silent compiler warning. */  
  //protocol name should come first
  if(0 == strcmp(key, "admin_username")){
    strcpy(temp_frp_connect_info.admin_username,data);
  }
  if(0 == strcmp(key, "admin_password")){
    strcpy(temp_frp_connect_info.admin_password,data);
  }
  if(0 == strcmp(key, "frp_server_addr")){
    strcpy(temp_frp_connect_info.frp_server_addr,data);
  }
  if(0 == strcmp(key, "frp_server_port")){
    strcpy(temp_frp_connect_info.frp_server_port,data);
  }
  if(0 == strcmp(key, "frp_token")){
    strcpy(temp_frp_connect_info.frp_token,data);
  }
  if(0 == strcmp(key, "http_remote_port")){
    strcpy(temp_frp_connect_info.http_remote_port,data);
  }
  if(0 == strcmp(key, "opc_ua_remote_port")){
    strcpy(temp_frp_connect_info.opc_ua_remote_port,data);
   
  }
  if(0 == strcmp(key, "ssh_remote_port")){
    strcpy(temp_frp_connect_info.ssh_remote_port,data);
  }
  return MHD_YES; 
}

enum MHD_Result PP_manage_program_update(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
  const char *filename, const char *content_type,
  const char *transfer_encoding, const char *data, uint64_t off, size_t size){
  struct connection_info_struct *con_info = coninfo_cls;
  (void)kind;              /* Unused. Silent compiler warning. */
  (void)filename;          /* Unused. Silent compiler warning. */
  (void)content_type;      /* Unused. Silent compiler warning. */
  (void)transfer_encoding; /* Unused. Silent compiler warning. */
  (void)off;               /* Unused. Silent compiler warning. */  
  //protocol name should come first
  if(0 == strcmp(key, "admin_username")){
    strcpy(temp_program_update_info.admin_username,data);
  }
  if(0 == strcmp(key, "admin_password")){
    strcpy(temp_program_update_info.admin_password,data);
  }
  if(0 == strcmp(key, "program_file_path")){
    strcpy(temp_program_update_info.program_file_path,data);
  }
  return MHD_YES; 
}

char new_username[32];
char new_password[32];
char old_username[32];
char old_password[32];
enum MHD_Result PP_modify_opc_username_password(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
  const char *filename, const char *content_type,
  const char *transfer_encoding, const char *data, uint64_t off, size_t size){
  struct connection_info_struct *con_info = coninfo_cls;
  (void)kind;              /* Unused. Silent compiler warning. */
  (void)filename;          /* Unused. Silent compiler warning. */
  (void)content_type;      /* Unused. Silent compiler warning. */
  (void)transfer_encoding; /* Unused. Silent compiler warning. */
  (void)off;               /* Unused. Silent compiler warning. */  
  //protocol name should come first
  if(0 == strcmp(key, "new_username")){
    strcpy(new_username,data);
  }
  if(0 == strcmp(key, "new_password")){
    strcpy(new_password,data);
  }
  if(0 == strcmp(key, "old_username")){
    strcpy(old_username,data);
  }
  if(0 == strcmp(key, "old_password")){
    strcpy(old_password,data);
  }
  return MHD_YES; 
}

//后面每创建出一种post请求的预处理函数，都要创建出一种匹配的结构体
enum MHD_Result PP_OPC_UA_history_data(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
  const char *filename, const char *content_type,
  const char *transfer_encoding, const char *data, uint64_t off, size_t size){
  struct connection_info_struct *con_info = coninfo_cls;
  (void)kind;              /* Unused. Silent compiler warning. */
  (void)filename;          /* Unused. Silent compiler warning. */
  (void)content_type;      /* Unused. Silent compiler warning. */
  (void)transfer_encoding; /* Unused. Silent compiler warning. */
  (void)off;               /* Unused. Silent compiler warning. */  
  //protocol name should come first

  //获取设备的用户名和密码信息
  printf("%s: %s\n",key,data);
  if(0 == strcmp(key, "admin_username")){
    strcpy(temp_POST_OPC_UA_history_data.admin_username,data);
    
  }
  if(0 == strcmp(key, "admin_password")){
    strcpy(temp_POST_OPC_UA_history_data.admin_password,data);      
  } 
  //获取历史数据里面的变量名
  if(0 == strcmp(key, "name")){
    strcpy(temp_POST_OPC_UA_history_data.name,data);
  }
  if(0 == strcmp(key, "begin_date")){
    strcpy(temp_POST_OPC_UA_history_data.begin_date,data);
  }
  if(0 == strcmp(key, "end_date")){
    strcpy(temp_POST_OPC_UA_history_data.end_date,data);
  }
  //protocol specify
  return MHD_YES; 
}


enum MHD_Result PP_OPC_UA_delete_var(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
  const char *filename, const char *content_type,
  const char *transfer_encoding, const char *data, uint64_t off, size_t size){
  struct connection_info_struct *con_info = coninfo_cls;
  (void)kind;              /* Unused. Silent compiler warning. */
  (void)filename;          /* Unused. Silent compiler warning. */
  (void)content_type;      /* Unused. Silent compiler warning. */
  (void)transfer_encoding; /* Unused. Silent compiler warning. */
  (void)off;               /* Unused. Silent compiler warning. */  
  //protocol name should come first

  //获取设备的用户名和密码信息
  if(0 == strcmp(key, "admin_username")){
    strcpy(temp_config_info.admin_username,data);
  }
  if(0 == strcmp(key, "admin_password")){
    strcpy(temp_config_info.admin_password,data);      
  } 
  //opc public property
  if(0 == strcmp(key, "name")){
    strcpy(temp_config_info.name,data);
  }
  if(0 == strcmp(key, "protocol")){
    strcpy(temp_config_info.protocol,data);
  }
  //protocol specify
  return MHD_YES; 
}

enum MHD_Result PP_opc_add_var(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
  const char *filename, const char *content_type,
  const char *transfer_encoding, const char *data, uint64_t off, size_t size){
  struct connection_info_struct *con_info = coninfo_cls;
  (void)kind;              /* Unused. Silent compiler warning. */
  (void)filename;          /* Unused. Silent compiler warning. */
  (void)content_type;      /* Unused. Silent compiler warning. */
  (void)transfer_encoding; /* Unused. Silent compiler warning. */
  (void)off;               /* Unused. Silent compiler warning. */  
  //protocol name should come first
  printf("%s : %s\n",key,data);
  if(0 == strcmp(key, "protocol")){
    strcpy(temp_config_info.protocol,data);
    // if(0 == strcmp(data, "modbus_tcp")){
    //   //pd = modbus_tcp;
    //   strcpy(temp_config_info.protocol,data);
    // }else if(0 == strcmp(data, "dlt_645")){
    //   //pd = dlt_645;
    //   strcpy(temp_config_info.protocol,data);      
    // }else if(0 == strcmp(data, "iec_104")){
    //   //pd = iec_104;
    //   strcpy(temp_config_info.protocol,data);        
    // }
  }
  //获取设备的用户名和密码信息
  if(0 == strcmp(key, "admin_username")){
    strcpy(temp_config_info.admin_username,data);
  }
  if(0 == strcmp(key, "admin_password")){
    strcpy(temp_config_info.admin_password,data);      
  } 
  //opc public property
  if(0 == strcmp(key, "name")){
    strcpy(temp_config_info.name,data);
  }else if(0 == strcmp(key, "var_type")){
    strcpy(temp_config_info.var_type,data);
  }

  /*
    DLT645协议的配置信息通过json的形式保存
  */
  if(0 == strcmp(key, "dlt645_param")){
    strcpy(temp_config_info.dlt645_param,data);
  } 
  /*
  modbus_rtu协议相关的参数，解除对于协议类型的限制
  */
  //json化的参数列表
  if(0 == strcmp(key, "rtu_param")){
    strcpy(temp_config_info.rtu_param,data);
  }  
  //Modbus_RTU协议

  /*
  modbus_tcp协议相关的参数，解除对于协议类型的限制
  */
  if(0 == strcmp(key, "ip_address")){
    strcpy(temp_config_info.ip_address,data);
  }else if(0 == strcmp(key, "port")){
    strcpy(temp_config_info.port,data);
  }else if(0 == strcmp(key, "register_type")){
    strcpy(temp_config_info.register_type,data);
  }else if(0 == strcmp(key, "begin_address")){
    //temp_config_info.begin_addr = atoi(data);
    strcpy(temp_config_info.begin_address,data);
  }else if(0 == strcmp(key, "offset_range")){
    //temp_config_info.offset_range = atoi(data);
    strcpy(temp_config_info.offset_range,data);
  }

  // if(pd == dlt_645){
  //   printf("%s : %s\n",key,data);
  //   if(0 == strcmp(key, "specification")){
  //     strcpy(temp_config_info.specification,data);
  //   }else if(0 == strcmp(key, "reg_address")){
  //     //temp_config_info.begin_addr = atoi(data);
  //     strcpy(temp_config_info.reg_address,data);
  //   }else if(0 == strcmp(key, "data_field")){
  //     //temp_config_info.offset_range = atoi(data);
  //     strcpy(temp_config_info.data_field,data);
  //   }
  // }else 

  /*
    IEC104协议相关的参数，接触对protocol参数的位置限制
  */
  if(0 == strcmp(key, "iec_ip_address")){
    strcpy(temp_config_info.iec_ip_address ,data);
  }else if(0 == strcmp(key, "iec_port")){
    strcpy(temp_config_info.iec_port,data);
  }else if(0 == strcmp(key, "iec_typeid")){
    strcpy(temp_config_info.iec_typeid,data);
  }else if(0 == strcmp(key, "iec_cot")){
    strcpy(temp_config_info.iec_cot,data);
  }else if(0 == strcmp(key, "iec_param")){
    strcpy(temp_config_info.iec_param,data);
  } 
  return MHD_YES; 
}

char* sql_insert_opc_var(){
    char sql[512] = "INSERT INTO opc_var_config (name,var_type,protocol) "  \
            "VALUES ";
    char* separate_begin = ", '";
    char* separate_end =  "'";
    char* sentence_end =  ");";
    char* sentence_begin = "('";
    strcat(sql,sentence_begin);
    strcat(sql,temp_config_info.name);
    strcat(sql,separate_end);
    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.var_type);
    strcat(sql,separate_end);
    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.protocol);
    strcat(sql,separate_end);
    strcat(sql,sentence_end);
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        //sqlite3_free(zErrMsg);
        return zErrMsg;
    }else{
        fprintf(stdout, "Records created successfully\n");
        return "success";
    }
}

//删除底层协议里面的配置信息
int sql_delete_protocol_config(){
    //
    char sql[512] = "delete from ";
    char* next = " where name = '";
    char* end = "';";
    if( 0 == strcmp(temp_config_info.protocol, "modbus_tcp")){
      strcat(sql,"modbus_tcp");
    }else if(0 == strcmp(temp_config_info.protocol, "dlt_645")){
        strcat(sql,"dlt_645_spec");   
    }else if(0 == strcmp(temp_config_info.protocol, "iec_104")){
        strcat(sql,"iec_104");    
    }else if(0 == strcmp(temp_config_info.protocol, "modbus_rtu")){
        strcat(sql,"modbus_rtu");    
    }
    strcat(sql,next);
    strcat(sql,temp_config_info.name);
    strcat(sql,end);
    //非常有用的调试语句，暴露了很多sql语句在组装时的编码错误
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
        return -1;
    }else{
        fprintf(stdout, "Records created successfully\n");
        return 0;
    }  
}


//sqlite的回调函数里面，调用一次，只会出一行的数据
//如果出现多行的情况,回调函数会被多次调用
static int Callback_OPC_UA_history_data(void *data, int argc, char **argv, char **azColName){
    int i;
    fprintf(stderr, "%s: ", (const char*)data);
    for(i=0; i<argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
        //不知道为什么，像UA_String这类复杂的数据结构不能用在sqlite的回调函数里面
        if(0 == strcmp(azColName[i], "data")){
            //二级数组在赋值的时候要考虑分配内存空间的问题
            //logins[http_colum_num].username = UA_STRING(argv[i]);
            strcpy(temp_history_data_buffer[http_colum_num],argv[i]); 
        }
        if(0 == strcmp(azColName[i], "date")){
            strcpy(temp_record_date_buffer[http_colum_num],argv[i]); 
        }
    }
    printf("\n");
    //对行号做自增的处理，用于信息录入时的一种下标机制
    http_colum_num++;
    printf("function finish\n");
    return 0;
}

void sql_select_OPC_UA_history_data(){         
    //设置http_colum_num为0，并且结束标志为false
    http_sql_cb_done = false;
    http_colum_num = 0;

    const char* data = "sql_select_OPC_UA_history_data\n";
    //select data from opc_history_data where name = '' and date >= '' and date<= ''; 
    char sql[512] = "select data,date from opc_history_data where name = '";
    strcat(sql,temp_POST_OPC_UA_history_data.name);
    strcat(sql,"' and date >= '");
    strcat(sql,temp_POST_OPC_UA_history_data.begin_date);
    strcat(sql,"' and date <= '");
    strcat(sql,temp_POST_OPC_UA_history_data.end_date);
    strcat(sql,"';");
  
    printf("[SQL]%s\n",sql);
    char *zErrMsg = 0;
    int rc;
    // modify callback
    rc = sqlite3_exec(db, sql,Callback_OPC_UA_history_data, (void*)data, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //sqlite3_free(zErrMsg);
        return zErrMsg;
    }else{
        fprintf(stdout, "SQL select done successfully\n");
        http_sql_cb_done = true;
        //把回调函数的结束标志放在这个语句后面，因为callback会被多次执行，并不能事先决定何时结束
    }
}


//删除opc ua里和名字对应的变量信息
int sql_delete_opc_var(){
    //
    char sql[512] = "delete from opc_var_config where name = '";
    char* end = "';";
    strcat(sql,temp_config_info.name);
    //传递的http参数已经被预处理器放入到全局变量中
    strcat(sql,end);
    //非常有用的调试语句，暴露了很多sql语句在组装时的编码错误
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
        return -1;
    }else{
        fprintf(stdout, "Records created successfully\n");
        return 0;
    }  
}



//参数和预处理函数有关的两个全局变量里面去获取
int sql_update_opc_auth(){
    //char sql[512] = "update opc_auth set password = '123456' where username = 'haosheng';";
    char sql[512] = "update opc_auth set password = '";
    char* begin = "',username = '";
    char* between = "' where username = '";
    char* end = "';";
    strcat(sql,new_password);
    //传递的http参数已经被预处理器放入到全局变量中
    strcat(sql,begin);
    strcat(sql,new_username);
    strcat(sql,between);
    strcat(sql,old_username);
    strcat(sql,end);
    //非常有用的调试语句，暴露了很多sql语句在组装时的编码错误
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
        return -1;
    }else{
        fprintf(stdout, "Records created successfully\n");
        return 0;
    }  
}


int sql_insert_opc_auth(){
    char sql[512] = "INSERT INTO opc_auth (username,password) "  \
            "VALUES ";
    char* separate_begin = ", '";
    char* separate_end =  "'";
    char* sentence_end =  ");";
    char* num_sep= ", ";
    char* sentence_begin = "('";

    strcat(sql,sentence_begin);
    //传递的http参数已经被预处理器放入到全局变量中
    strcat(sql,new_username);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,new_password);
    strcat(sql,separate_end);

    strcat(sql,sentence_end);
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
        return -1;
    }else{
        fprintf(stdout, "Records created successfully\n");
        return 0;
    }  
}

void sql_insert_modbus_rtu(){
            // char* sql1 = "INSERT INTO modbus_tcp_reg_config (id,reg_type,begin_addr,offset_range) "  
          //       "VALUES (3, 'register', 1, 1); " 
    char sql[512] = "INSERT INTO modbus_rtu (name,rtu_param) "  \
            "VALUES ";
    char* separate_begin = ", '";
    char* separate_end =  "'";
    char* sentence_end =  ");";
    char* num_sep= ", ";
    char* sentence_begin = "('";

    strcat(sql,sentence_begin);
    strcat(sql,temp_config_info.name);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.rtu_param);
    strcat(sql,separate_end);
    
    strcat(sql,sentence_end);
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Records created successfully\n");
    }
}


void sql_insert_modbus_tcp(){
            // char* sql1 = "INSERT INTO modbus_tcp_reg_config (id,reg_type,begin_addr,offset_range) "  
          //       "VALUES (3, 'register', 1, 1); " 
    char sql[512] = "INSERT INTO modbus_tcp (name,ip_address,port,register_type,begin_address,offset_range) "  \
            "VALUES ";
    char* separate_begin = ", '";
    char* separate_end =  "'";
    char* sentence_end =  ");";
    char* num_sep= ", ";
    char* sentence_begin = "('";

    strcat(sql,sentence_begin);
    strcat(sql,temp_config_info.name);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.ip_address);
    strcat(sql,separate_end);
    
    strcat(sql,num_sep);
    strcat(sql,temp_config_info.port);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.register_type);
    strcat(sql,separate_end);

    strcat(sql,num_sep);
    strcat(sql,temp_config_info.begin_address);
    
    strcat(sql,num_sep);
    strcat(sql,temp_config_info.offset_range);

    // strcat(sql,separate_begin);
    // strcat(sql,temp_config_info.modbus_tcp_param);
    // strcat(sql,separate_end);

    strcat(sql,sentence_end);
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Records created successfully\n");
    }
}

void sql_insert_dlt_645(){
            // char* sql1 = "INSERT INTO modbus_tcp_reg_config (id,reg_type,begin_addr,offset_range) "  
          //       "VALUES (3, 'register', 1, 1); " 
    char sql[512] = "INSERT INTO dlt_645 (name,param) "  \
            "VALUES ";
    char* separate_begin = ", '";
    char* separate_end =  "'";
    char* sentence_end =  ");";
    char* num_sep= ", ";
    char* sentence_begin = "('";

    strcat(sql,sentence_begin);
    strcat(sql,temp_config_info.name);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.dlt645_param);
    strcat(sql,separate_end);
    
    strcat(sql,sentence_end);
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Records created successfully\n");
    }
}

void sql_insert_iec_104_measure(){
            // char* sql1 = "INSERT INTO modbus_tcp_reg_config (id,reg_type,begin_addr,offset_range) "  
          //       "VALUES (3, 'register', 1, 1); " 
    char sql[512] = "INSERT INTO iec_104 (name,ip_address,port,typeid,cot,param) "  \
            "VALUES ";
    char* separate_begin = ", '";
    char* separate_end =  "'";
    char* sentence_end =  ");";
    char* num_sep= ", ";
    char* sentence_begin = "('";

    strcat(sql,sentence_begin);
    strcat(sql,temp_config_info.name);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.iec_ip_address);
    strcat(sql,separate_end);
    
    strcat(sql,num_sep);
    strcat(sql,temp_config_info.iec_port);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.iec_typeid);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.iec_cot);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,temp_config_info.iec_param);
    strcat(sql,separate_end);
    strcat(sql,sentence_end);
    printf("%s\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //遇到异常重启程序的指令，在开发阶段不使用
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Records created successfully\n");
    }
}


enum MHD_Result RESTful_API_Entry(void *cls, struct MHD_Connection *connection,
                                     const char *url, const char *method,
                                     const char *version, const char *upload_data,
                                     size_t *upload_data_size, void **con_cls)
{
  (void)cls;     /* Unused. Silent compiler warning. */
  //(void)url;     /* Unused. Silent compiler warning. */
  (void)version; /* Unused. Silent compiler warning. */
  if (NULL == *con_cls)
  {
    //printf("RESTful_API_Entry\n");
    struct connection_info_struct *con_info;
    con_info = malloc(sizeof(struct connection_info_struct));
    if (NULL == con_info)
      return MHD_NO;
    con_info->answerstring = NULL;
    if (0 == strcmp(method, "POST"))
    {
      if(0 == strcmp(url, "/opc_ua/add_var")){
        // preprocess user request param,get info
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_opc_add_var, (void *)con_info);        
      }
      //PP_ 函数名的前缀是post processor后处理器的缩写
      //add说明还要支持delete和modify两类的动词
      if(0 == strcmp(url, "/opc_auth/add")){
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_modify_opc_username_password, (void *)con_info);        
      }
      //更新现在的默认账号密码，和增加账号使用相同的接口
      if(0 == strcmp(url, "/opc_auth/update")){
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_modify_opc_username_password, (void *)con_info);        
      }
      //不做数据库操作，直接写入frp的配置文件
      if(0 == strcmp(url, "/frp_info/update")){
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_update_frp_connect_info, (void *)con_info);        
      }
      if(0 == strcmp(url, "/opc_ua/delete_var")){
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_OPC_UA_delete_var, (void *)con_info);          
      }
      if(0 == strcmp(url, "/opc_ua/history_data")){
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_OPC_UA_history_data, (void *)con_info);          
      }
      if(0 == strcmp(url, "/manage/program_update")){
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_manage_program_update, (void *)con_info);          
      } 
      if(0 == strcmp(url, "/manage/heart_beat")){
        con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE,
                                                   PP_manage_program_update, (void *)con_info);          
      }        
      if (NULL == con_info->postprocessor)
      {
        free(con_info);
        return MHD_NO;
      }
      con_info->connectiontype = POST;
    }
    else
      con_info->connectiontype = GET;
    *con_cls = (void *)con_info;
    return MHD_YES;
  }
  if (0 == strcmp(method, "GET"))
  {
    //opc_ALL_var_name();
    return send_page(connection, askpage);
  }
  if (0 == strcmp(method, "POST"))
  {
    if(0 == strcmp(url, "/all")){
      struct connection_info_struct *con_info = *con_cls;
      if(*upload_data_size != 0){
        /**must have these two sentence for each request**/
        MHD_post_process(con_info->postprocessor, upload_data,
                  *upload_data_size);
        *upload_data_size = 0;
        //opc_ALL_var_name();
        return MHD_YES;
      }else{
          return send_page(connection, errorpage);
      }
    }
    if(0 == strcmp(url, "/opc_ua/add_var")){
      /*拆分为函数以后，参数按照这个格式，函数执行完以后必须加上一个return！！！！
      否则会报很严重的运行时错误*/
       return handler_add_var(*con_cls,upload_data_size,connection,upload_data);
    }else if(0 == strcmp(url, "/user/login")){
      /*拆分为函数以后，参数按照这个格式，函数执行完以后必须加上一个return！！！！
      否则会报很严重的运行时错误*/
       return handler_add_var(*con_cls,upload_data_size,connection,upload_data);
    }else if(0 == strcmp(url, "/opc_auth/add")){
      return handler_opc_auth(*con_cls,upload_data_size,connection,upload_data);
    }else if(0 == strcmp(url, "/opc_auth/update")){
      return handler_opc_auth_update(*con_cls,upload_data_size,connection,upload_data);
    }else if(0 == strcmp(url, "/frp_info/update")){
      return handler_frp_info_update(*con_cls,upload_data_size,connection,upload_data);
    }else if(0 == strcmp(url, "/opc_ua/delete_var")){
      return handler_OPC_UA_delete_var(*con_cls,upload_data_size,connection,upload_data);
    }else if(0 == strcmp(url, "/opc_ua/history_data")){
      return handler_OPC_UA_history_data(*con_cls,upload_data_size,connection,upload_data);     
    }else if(0 == strcmp(url,"/manage/program_update")){
      return handler_manage_program_update(*con_cls,upload_data_size,connection,upload_data);     
    }else if(0 == strcmp(url,"/manage/heart_beat")){
      return handler_manage_program_restart(*con_cls,upload_data_size,connection,upload_data);     
    }
  }
  return send_page(connection, errorpage);
}

int ini_file_frp_info_update(){
  FILE *fp;
  if( (fp=fopen("./frp_0.46.1_linux_amd64/frpc.ini","w")) == NULL ){
      printf("Fail to open file!\n");
      exit(0);  //退出程序（结束程序）
  } 
  //通过strcat拼凑字符串
  char content[512]= 
    "[common]\n\
    authenticate_new_work_conns = true\n\
    authentication_method = token\n\
    token = ";
  //在代码出现大的语法错误的时候，自动补全有很大的概率会失效
  strcat(content,temp_frp_connect_info.frp_token);
  // “\n”是用来补充上一行的错误
  char* next= 
    "\nserver_addr = ";
  strcat(content,next);
  strcat(content,temp_frp_connect_info.frp_server_addr);

  char* next_two= 
    "\nserver_port = "; 
  strcat(content,next_two);
  strcat(content,temp_frp_connect_info.frp_server_port);

  char* next_three= 
    "\n\
    [opc ua server]\n\
    type = tcp\n\
    local_ip = 127.0.0.1\n\
    local_port = 4000\n\
    remote_port = ";
  strcat(content,next_three);
  strcat(content,temp_frp_connect_info.opc_ua_remote_port);

  char* next_four= 
    "\n\n\
    [Config Web Server]\n\
    type = tcp\n\
    local_ip = 127.0.0.1\n\
    local_port = 9999\n\
    remote_port = ";
  strcat(content,next_four);
  strcat(content,temp_frp_connect_info.http_remote_port);
  //文本拼接完成，写入到文件中

  char* next_five= 
    "\n\n\
    [ssh]\n\
    type = tcp \n\            
    local_ip = 127.0.0.1\n\ 
    local_port = 22 \n\       
    remote_port = ";  
  strcat(content,next_five);
  strcat(content,temp_frp_connect_info.ssh_remote_port);

  fputs(content,fp);
  fclose(fp); 
  return 0;
}

enum MHD_Result handler_OPC_UA_delete_var(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{

      cJSON* cjson_test = NULL;
      /* 创建一个JSON数据对象(链表头结点) */
      cjson_test = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(cjson_test, "OP", "OPC_UA_delete_var");
      //通过sql语句进行插入,返回值为0说明插入正常

      /*判断用户发起请求的密码和现有的密码是否是一致的，
      目前默认只有一个管理员账号能够访问设备*/
      if(strcmp(temp_username[0],temp_config_info.admin_username)==0 
        && strcmp(temp_password[0],temp_config_info.admin_password)==0){
        //删除opc和底层协议里面的对应信息
        if(sql_delete_opc_var()==0 && sql_delete_protocol_config()==0){
          //删除操作成功以后，就重启程序，OPC UA重新读取数据库里的数据来创建变量列表
          cJSON_AddStringToObject(cjson_test, "STATUS", "SUCCESS");
          reboot = true;
        }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-SQL statement");
        }        
      }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-Unauthorized user");
      }
      //后续要考虑把OPC_addVariable的返回值体现在JSON里面
      // 返回最终的 POST 请求
      /* 打印JSON对象(整条链表)的所有数据 */
      const char *res_post = cJSON_Print(cjson_test);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      // if(reboot){
      //   execve("opc", NULL, NULL);
      // }
      return ret;
    }
}


enum MHD_Result handler_OPC_UA_history_data(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{
      //处理函数启动的时候，分配内存空间，查询结束后释放，13KB一次还好，多次查询，还是会被耗尽的
      //或者直接固定分配13KB

      /* 创建一个JSON数据对象(链表头结点) */
      cJSON* root = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(root, "request_path", "/opc_ua/history_data");
      //通过sql语句进行插入,返回值为0说明插入正常

      /*判断用户发起请求的密码和现有的密码是否是一致的，
      目前默认只有一个管理员账号能够访问设备*/
      if(strcmp(temp_username[0],temp_POST_OPC_UA_history_data.admin_username)==0 
        && strcmp(temp_password[0],temp_POST_OPC_UA_history_data.admin_password)==0){
        
        //编写查询语句
        sql_select_OPC_UA_history_data();
        while (!http_sql_cb_done){}
        if(http_colum_num==0){
          cJSON_AddStringToObject(root,"STATUS","ERROR-No record exist or incorrect variable name");
        }else{
          //行号在执行完最后一次操作以后，依然会加1，应该直接就可以用
          cJSON *data_array = cJSON_CreateArray();
          for(int i=0;i<http_colum_num;i++){
            cJSON *record_item = cJSON_CreateObject();          
            cJSON *record_data = cJSON_Parse(temp_history_data_buffer[i]);
            cJSON_AddItemToObject(record_item, "record", record_data);
            // cJSON *record_date = cJSON_Parse(temp_record_date_buffer[i]);
            // cJSON_AddItemToObject(record_item, "date", record_date);
            cJSON_AddStringToObject(record_item, "date", temp_record_date_buffer[i]);
            cJSON_AddItemToArray(data_array, record_item);
          }
          //cJSON *data_array = cJSON_CreateStringArray(temp_history_data_buffer, http_colum_num);
          cJSON_AddItemToObject(root, "history_data_array", data_array);
          cJSON_AddStringToObject(root, "STATUS", "SUCCESS");  
        }
      }else{
          cJSON_AddStringToObject(root, "STATUS", "ERROR-Unauthorized user");
      }
      const char *res_post = cJSON_Print(root);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      cJSON_Delete(root);
      return ret;
    }
}

enum MHD_Result handler_frp_info_update(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{

      cJSON* cjson_test = NULL;
      /* 创建一个JSON数据对象(链表头结点) */
      cjson_test = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(cjson_test, "request_path", "/frp_info/update");
      //通过sql语句进行插入,返回值为0说明插入正常

      /*判断用户发起请求的密码和现有的密码是否是一致的，
      目前默认只有一个管理员账号能够访问设备*/
      if(strcmp(temp_username[0],temp_frp_connect_info.admin_username)==0 
        && strcmp(temp_password[0],temp_frp_connect_info.admin_password)==0){
        /*
        在修改默认账号密码的时候，能够支持把现有的账号密码都修改掉，即使账号是作为主键
        */
        if(0==ini_file_frp_info_update()){
          //cJSON_AddStringToObject(cjson_test, "SUCCESS", "Check");
          //如果配置文件修改成功，直接重启程序，让frp用新的参数进行连接
          //只有操作失败才会返回提示报文
          //execve("opc", NULL, NULL)这种重启网关的方式不合理，后续已经改为在node red里面通过指令去重启网关
          char buf[1024];  
          FILE * p_file = NULL; 
          //把frp的参数也传递到ip白名单里面去,通过shell脚本执行防火墙的配置
          //shell脚本在C语言程序调用之前
          char sh_cmd[512] = "./secret/white_list.sh ";
          strcat(sh_cmd,temp_frp_connect_info.frp_server_addr);
          p_file = popen(sh_cmd, "r");  
          if (!p_file) {  
              fprintf(stderr, "Erro to popen");  
          }  
          while (fgets(buf, 1024, p_file) != NULL) {  
              fprintf(stdout, "%s", buf);  
          }  
          pclose(p_file);
          // p_file = popen("./frp_0.46.1_linux_amd64/frpc -c ./frp_0.46.1_linux_amd64/frpc.ini", "r");  
          // if (!p_file) {  
          //     fprintf(stderr, "Erro to popen");  
          // }  
          //只要不重复监视返回值，http请求就可以正常返回JSON报文，
          // while (fgets(buf, 1024, p_file) != NULL) {  
          //     fprintf(stdout, "%s", buf);  
          // }  
          // pclose(p_file);
          cJSON_AddStringToObject(cjson_test, "STATUS", "SUCCESS-update frp and iptable white list");
        }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-update frp error");
        }        
      }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-Unauthorized user");
      }
                
      //后续要考虑把OPC_addVariable的返回值体现在JSON里面
      // 返回最终的 POST 请求
      /* 打印JSON对象(整条链表)的所有数据 */
      const char *res_post = cJSON_Print(cjson_test);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      return ret;
    }
}


static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
  struct FtpFile *out = (struct FtpFile *)stream;
  if(!out->stream) {
    /* open file for writing */
    out->stream = fopen(out->filename, "wb");
    if(!out->stream)
      return -1; /* failure, cannot open file to write */
  }
  return fwrite(buffer, size, nmemb, out->stream);
}

enum MHD_Result handler_manage_program_restart(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{

      cJSON* cjson_test = NULL;
      /* 创建一个JSON数据对象(链表头结点) */
      cjson_test = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(cjson_test, "request_path", "/manage/program_restart");
      //通过sql语句进行插入,返回值为0说明插入正常

      /*判断用户发起请求的密码和现有的密码是否是一致的，
      目前默认只有一个管理员账号能够访问设备*/
      if(strcmp(temp_username[0],temp_program_update_info.admin_username)==0 
        && strcmp(temp_password[0],temp_program_update_info.admin_password)==0){
          cJSON_AddStringToObject(cjson_test, "STATUS", "SUCCESS-live");
          
      }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-Unauthorized user");
      }
      //后续要考虑把OPC_addVariable的返回值体现在JSON里面
      // 返回最终的 POST 请求
      /* 打印JSON对象(整条链表)的所有数据 */
      const char *res_post = cJSON_Print(cjson_test);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      return ret;
    }
}

enum MHD_Result handler_manage_program_update(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{

      cJSON* cjson_test = NULL;
      /* 创建一个JSON数据对象(链表头结点) */
      cjson_test = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(cjson_test, "request_path", "/manage/program_update");
      //通过sql语句进行插入,返回值为0说明插入正常

      /*判断用户发起请求的密码和现有的密码是否是一致的，
      目前默认只有一个管理员账号能够访问设备*/
      if(strcmp(temp_username[0],temp_program_update_info.admin_username)==0 
        && strcmp(temp_password[0],temp_program_update_info.admin_password)==0){
        //删除opc和底层协议里面的对应信息
          CURL *curl;
          CURLcode res;
          struct FtpFile ftpfile = {
            "curl.tar.gz", /* name to store the file as if successful */
            NULL
          };
          curl_global_init(CURL_GLOBAL_DEFAULT);
          curl = curl_easy_init();
          if(curl) {
            // curl_easy_setopt(curl, CURLOPT_URL,
            //                 "ftp://haosheng_ftp:123@192.168.18.99:21/opc");
            curl_easy_setopt(curl, CURLOPT_URL,temp_program_update_info.program_file_path);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
            /* Set a pointer to our struct to pass to the callback */
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
            /* Switch on full protocol/debug output */
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
            res = curl_easy_perform(curl);
            /* always cleanup */
            curl_easy_cleanup(curl);
            if(CURLE_OK != res) {
              /* we failed */
              fprintf(stderr, "curl told us %d\n", res);
              cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-CURL");
            }else{
              cJSON_AddStringToObject(cjson_test, "STATUS", "SUCCESS");
              reboot = true;
            }
          }
          if(ftpfile.stream)
            fclose(ftpfile.stream); /* close the local file */
          curl_global_cleanup();      
      }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-Unauthorized user");
      }
      //后续要考虑把OPC_addVariable的返回值体现在JSON里面
      // 返回最终的 POST 请求
      /* 打印JSON对象(整条链表)的所有数据 */
      const char *res_post = cJSON_Print(cjson_test);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      // if(reboot){
      //   execve("opc", NULL, NULL);
      // }
      return ret;
    }
}

enum MHD_Result handler_opc_auth_update(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{

      cJSON* cjson_test = NULL;
      /* 创建一个JSON数据对象(链表头结点) */
      cjson_test = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(cjson_test, "path", "/opc_auth/update");
      //通过sql语句进行插入,返回值为0说明插入正常

      /*判断用户发起请求的密码和现有的密码是否是一致的，
      目前默认只有一个管理员账号能够访问设备*/
      if(strcmp(temp_username[0],old_username)==0 && strcmp(temp_password[0],old_password)==0){
        /*
        在修改默认账号密码的时候，能够支持把现有的账号密码都修改掉，即使账号是作为主键
        */
        if(0==sql_update_opc_auth()){
          //数据库的配置修改成功以后，node-red在解析返回报文以后自动重启服务器
          cJSON_AddStringToObject(cjson_test, "STATUS", "SUCCESS");
        }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-SQL_ERROR");
        }        
      }else{
          cJSON_AddStringToObject(cjson_test, "STATUS", "ERROR-Unauthorized user");
      }
        //后续要考虑把OPC_addVariable的返回值体现在JSON里面
          // 返回最终的 POST 请求
      /* 打印JSON对象(整条链表)的所有数据 */
      const char *res_post = cJSON_Print(cjson_test);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      /*密码在修改完以后，程序自动重启生效，有返回报文说明修改异常*/
      return ret;
    }
}

enum MHD_Result handler_opc_auth(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{
      cJSON* cjson_test = NULL;
      /* 创建一个JSON数据对象(链表头结点) */
      cjson_test = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(cjson_test, "name", "HaoSheng");
      //通过sql语句进行插入,返回值为0说明插入正常
      if(0==sql_insert_opc_auth()){
        cJSON_AddTrueToObject(cjson_test, "opc_auth_add");
      }else{
        cJSON_AddFalseToObject(cjson_test, "opc_auth_add");
      }
        //后续要考虑把OPC_addVariable的返回值体现在JSON里面
          // 返回最终的 POST 请求
      /* 打印JSON对象(整条链表)的所有数据 */
      const char *res_post = cJSON_Print(cjson_test);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      return ret;
    }
}

enum MHD_Result handler_add_var(struct connection_info_struct *con_info,size_t *upload_data_size,
        struct MHD_Connection *connection,const char *upload_data){
    //struct connection_info_struct *con_info = *con_cls;
    //if(*upload_data_size != 0){
      /**must have these two sentence for each request**/
    struct MHD_Response *response;
    struct Request *request;
    struct Session *session;
    int ret;
    if(*upload_data_size != 0){
      MHD_post_process(con_info->postprocessor, upload_data,
        *upload_data_size);
      *upload_data_size = 0;
      //printf("one round!\n");
      return MHD_YES;
    }else{

        //后续要考虑把OPC_addVariable的返回值体现在JSON里面
          // 返回最终的 POST 请求
      cJSON* root = NULL;
      /* 创建一个JSON数据对象(链表头结点) */
      root = cJSON_CreateObject();
      /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
      cJSON_AddStringToObject(root, "request_path", "/opc_ua/add_var");
      //通过sql语句进行插入,返回值为0说明插入正常

      /*判断用户发起请求的密码和现有的密码是否是一致的，
      目前默认只有一个管理员账号能够访问设备*/
      // printf("1.%s %s\n",temp_username[0],temp_config_info.admin_username);读取键值对的时候key value不分
      // printf("2.%s %s\n",temp_password[0],temp_config_info.admin_password);
      if(strcmp(temp_username[0],temp_config_info.admin_username)==0 && 
        strcmp(temp_password[0],temp_config_info.admin_password)==0){
        /*
        在修改默认账号密码的时候，能够支持把现有的账号密码都修改掉，即使账号是作为主键
        */
        //首先将opc的相关变量进行插入
        /*
        参数在sql插入之前，和动作进行之前，需要进行过滤，只有满足要求才能继续
        不知道这一步要不要放在预处理的地方
        */
        char* ret_str = NULL;
        //首先要判断用户提供的协议是否受支持
        if(0 == strcmp(temp_config_info.protocol,"modbus_tcp")||
          0 == strcmp(temp_config_info.protocol,"iec_104")||
          0 == strcmp(temp_config_info.protocol,"modbus_rtu")||
           0 == strcmp(temp_config_info.protocol,"dlt_645")){
          //处理变量名重复的问题，数据库定义的时候，都设置了对非空的要求
          ret_str = sql_insert_opc_var();
          if(0 == strcmp(ret_str,"success")){
            if(0 == strcmp(temp_config_info.protocol,"modbus_tcp")){
              sql_insert_modbus_tcp();
            }else if(0 == strcmp(temp_config_info.protocol,"modbus_rtu")){
              sql_insert_modbus_rtu();
            }else if(0 == strcmp(temp_config_info.protocol,"dlt_645")){
              sql_insert_dlt_645();
            }else if(0 == strcmp(temp_config_info.protocol,"iec_104")){
              sql_insert_iec_104_measure();
            }
            int ret = OPC_addVariable(haussentech_opc_server,
              temp_config_info.name,temp_config_info.protocol);   
            if(ret == 0){
              cJSON_AddStringToObject(root, "STATUS", "SUCCESS");   
            }else if(ret == -1){
              //同时把之前插入的信息给删除掉，因为这些信息无效
              if(sql_delete_opc_var()==0 && sql_delete_protocol_config()==0){
                  cJSON_AddStringToObject(root, "STATUS", "ERROR-Param invaild"); 
              }
            }else{
              cJSON_AddStringToObject(root, "STATUS", "ERROR-OPC_addVariable Error!!!");
            }
          }else{
            char error_str[64]="ERROR-";
            strcat(error_str,ret_str);
            cJSON_AddStringToObject(root,"STATUS",error_str);
          }
        }else{
          cJSON_AddStringToObject(root,"STATUS","ERROR-False spell protocol name or unsupported protocol.");
        }
      }else{
          cJSON_AddStringToObject(root, "STATUS", "ERROR-Unauthorized user");
      }
      //后续要考虑把OPC_addVariable的返回值体现在JSON里面
      //返回最终的 POST 请求
      /*打印JSON对象(整条链表)的所有数据 */
      const char *res_post = cJSON_Print(root);
      printf("%s\n", res_post);
      //const char *res_post = "{\"result\": \"success\", \"message\":\"you call post method.\"}";
      response = MHD_create_response_from_buffer(strlen(res_post),
                                                (void *)res_post,
                                                MHD_RESPMEM_PERSISTENT);
      MHD_add_response_header(response, "content-type", "applicaton/json"); // 返回格式可以是 json
      //新增代码【实验结论内存占用上升与未释放后处理器无关】
      //MHD_destroy_post_processor(con_info->postprocessor);

      ret = MHD_queue_response(connection,
                              MHD_HTTP_OK,
                              response);
      MHD_destroy_response(response);
      return ret;
    }
}

enum MHD_Result send_page(struct MHD_Connection *connection, const char *page)
{
  enum MHD_Result ret;
  struct MHD_Response *response;
  response =
      MHD_create_response_from_buffer(strlen(page), (void *)page,
                                      MHD_RESPMEM_PERSISTENT);
  if (!response)
    return MHD_NO;
  ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
  MHD_destroy_response(response);
  return ret;
}


